using System;
using System.Collections.Generic;
using System.Reflection;
using Unity.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Networking;
using UnityEngine.UI;
using System.Security.Cryptography;
using System.Diagnostics;

namespace Framework
{
    public static partial class Utils
    {
        public static class Unity
        {
            public static string GetStreamingAssets(string path)
            {
                /*
                StreamingAssets 目录不同平台对应的URL是不一样的，如下：
                Windows平台 file:///D:/DATA/StreamingAssets/data.json
                WebGl平台 http://localhost/StreamingAssets/data.json
                Android平台 jar:file:///data/app/xxx!/assets/data.json
                IOS平台 Application/ xxxxxxxx - xxxx - xxxx - xxxx - xxxxxxxxxxxx / xxx.app / Data / Raw
                这时候最好通过构造Uri()的方式来规避平台的差异
                */
                return new System.Uri(System.IO.Path.Combine(Application.streamingAssetsPath, path)).AbsoluteUri;
            }
            public static List<T> GetChilds<T>(GameObject gameObject, bool includeInactive) where T : Component
            {
                T[] array = gameObject.GetComponentsInChildren<T>(includeInactive);
                List<T> list = new List<T>();
                foreach (var item in array)
                {
                    if (item.transform != gameObject.transform)
                    {
                        list.Add(item);
                    }
                }
                return list;
            }

            public static List<T> GetChilds<T>(Component component, bool includeInactive) where T : Component
            {
                T[] array = component.GetComponentsInChildren<T>(includeInactive);

                List<T> list = new List<T>();
                foreach (var item in array)
                {
                    if (item.transform != component.transform)
                    {
                        list.Add(item);
                    }
                }
                return list;
            }
            public static void GetChilds(Transform target, List<Transform> list, System.Func<Transform, bool> filter)
            {
                var len = target.childCount;
                for (int i = 0; i < len; i++)
                {
                    var child = target.GetChild(i);
                    list.Add(child);
                    if (!filter(child)) continue;
                    GetChilds(child, list, filter);
                }
            }
            public static void Destory(UnityEngine.Object obj)
            {
                if (obj != null)
                {
                    UnityEngine.Object.Destroy(obj);
                }
            }
            public static void SetParent(Transform parent, Transform child)
            {
                if (null == parent || null == child)
                {
                    return;
                }
                child.SetParent(parent);
                child.localPosition = Vector3.zero;
                child.localEulerAngles = Vector3.zero;
                child.localScale = Vector3.one;
            }
            public static GameObject AddChild(Transform parent, GameObject child)
            {
                if (null == parent || null == child)
                {
                    return null;
                }
                GameObject newChild = GameObject.Instantiate(child);
                SetParent(parent, newChild.transform);
                return newChild;
            }
            public static void SetActive(Component component, bool value)
            {
                if (component != null)
                {
                    SetActive(component.gameObject, value);
                }
            }
            public static void SetActive(GameObject gameObject, bool value)
            {
                if (gameObject != null && gameObject.activeSelf != value)
                {
                    gameObject.SetActive(value);
                }
            }
            public static void SetEnabled(Behaviour behaviour, bool value)
            {
                if (behaviour != null)
                {
                    behaviour.enabled = value;
                }
            }
            public static void SetLocalScale(Component component, Vector3 value)
            {
                if (component != null)
                {
                    component.transform.localScale = value;
                }
            }
            public static T GetComponent<T>(GameObject target, bool addMode = true) where T : Component
            {
                var obj = target.GetComponent<T>();
                if (obj == null && addMode)
                {
                    var c = target.AddComponent<T>();
                    obj = c as T;
                }
                return obj;
            }
            public static T GetComponent<T>(Transform target, bool addMode = true) where T : Component
            {
                return GetComponent<T>(target.gameObject, addMode);
            }
            public static void SetLocalScale(GameObject gameObject, Vector3 value)
            {
                if (gameObject != null)
                {
                    gameObject.transform.localScale = value;
                }
            }
            public static void SetLocalPosition(Component component, Vector3 value)
            {
                if (component != null)
                {
                    component.transform.localPosition = value;
                }
            }
            public static void SetLocalRotation(Component component, Vector3 value)
            {
                if (component != null)
                {
                    component.transform.localEulerAngles = value;
                }
            }
            public static void SetText(UnityEngine.UI.Text uiText, string content)
            {
                if (uiText != null && uiText.text != content.ToString())
                {
                    uiText.text = content.ToString();
                }
            }
            public static void SetImage(Image image, Sprite sprite, bool nativeSize = false)
            {
                if (image == null)
                {
                    return;
                }
                image.sprite = sprite;
                if (nativeSize)
                {
                    image.SetNativeSize();
                }
            }
            public static void SetRawImage(RawImage rawImage, Texture texture, bool nativeSize = false)
            {
                if (rawImage == null)
                {
                    return;
                }
                rawImage.texture = texture;
                if (nativeSize)
                {
                    rawImage.SetNativeSize();
                }
            }
            public static void SetSlider(Slider slider, float value)
            {
                if (slider != null)
                {
                    slider.value = Mathf.Clamp01(value);
                }
            }
            public static void SetToggle(Toggle toggle, bool value)
            {
                if (toggle != null)
                {
                    toggle.isOn = value;
                }
            }
            public static void SetToggleGroup(Toggle toggle, ToggleGroup group)
            {
                if (toggle != null)
                {
                    toggle.group = group;
                }
            }
            public static void SetColor(Graphic graphic, Color color)
            {
                if (graphic != null)
                {
                    graphic.color = color;
                }
            }
            public static void SetInput(InputField input, string text)
            {
                if (input != null)
                {
                    input.text = text;
                }
            }
            public static void SetButtonEnabled(Selectable selectable, bool enabled)
            {
                if (selectable != null)
                {
                    selectable.interactable = enabled;
                }
            }
            public static void SetAlpha(CanvasGroup group, float alpha)
            {
                if (group != null && group.alpha != alpha)
                {
                    group.alpha = alpha;
                }
            }


            public static void SetImageFill(Image image, float fillAmount)
            {
                if (image != null)
                {
                    image.fillAmount = fillAmount;
                }
            }
            public static GameObject GetOverUI(GraphicRaycaster gr, PointerEventData eventData)
            {
                List<RaycastResult> results = new List<RaycastResult>();
                gr.Raycast(eventData, results);
                if (results.Count != 0)
                {
                    return results[0].gameObject;
                }
                return null;
            }
            public static void SetFullScreen(RectTransform rectTransform)
            {
                if (null != rectTransform)
                {
                    rectTransform.anchorMin = new Vector2(0f, 0f);
                    rectTransform.anchorMax = new Vector2(1f, 1f);
                    rectTransform.offsetMin = new Vector2(0f, 0f);
                    rectTransform.offsetMax = new Vector2(1f, 1f);
                    rectTransform.sizeDelta = new Vector2(0f, 0f);
                    rectTransform.anchoredPosition = new Vector2(0, 0);
                }
            }
            public static bool IsPointerOverGameObject(int fingerId = -1)
            {
                if (EventSystem.current == null)
                {
                    return false;
                }
                if (fingerId < 0)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        if (EventSystem.current.IsPointerOverGameObject(i))
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (EventSystem.current.IsPointerOverGameObject(fingerId))
                    {
                        return true;
                    }
                }
                return EventSystem.current.IsPointerOverGameObject();
            }
            public static bool IsUnityWebRequestError(UnityWebRequest value)
            {
#if UNITY_2020_1_OR_NEWER
                return value.result == UnityWebRequest.Result.ConnectionError || value.result == UnityWebRequest.Result.ConnectionError || value.result == UnityWebRequest.Result.ProtocolError;
#else
                return value.isHttpError || value.isNetworkError;
#endif
            }
            public static Vector3 ScreenPointToUIPoint(RectTransform container, Vector3 screenPosition, Camera uiCamera = null)
            {
                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(container, screenPosition, uiCamera, out Vector2 localPosition))
                {
                    return localPosition;
                }
                return Vector3.zero;
            }
            public static void SetUIPointFromScreenPoint(RectTransform target, Vector3 screenPosition, Camera uiCamera = null)
            {
                if (target == null)
                {
                    return;
                }
                if (target.parent is RectTransform parent)
                {
                    if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parent, screenPosition, uiCamera, out Vector2 localPosition))
                    {
                        target.localPosition = localPosition;
                    }
                }
            }
            /// <summary>
            /// 世界坐标屏幕坐标
            /// </summary>
            /// <param name="target">UI组件</param>
            /// <param name="renderCamera">screen space - overlay 模式下为空</param>
            /// <returns></returns>
            public static Vector2 WorldToScreenPoint(RectTransform target, Camera renderCamera = null)
            {
                return RectTransformUtility.WorldToScreenPoint(renderCamera, target.position);
            }

            public static Vector3 WorldToScreenPoint(Vector3 worldPosition, Camera renderCamera = null)
            {
                if (renderCamera == null)
                {
                    return worldPosition;
                }
                return renderCamera.WorldToScreenPoint(worldPosition);
            }
            public static Vector3 ScreenToWorldPoint(Camera renderCamera, Vector3 screenPosition)
            {
                return renderCamera.ScreenToWorldPoint(screenPosition);
            }
            /**
            /// <summary>
            /// 
            /// </summary>
            /// <param name="baseRect">canvas 的 RectTransform</param>
            /// <param name="screenPosition">屏幕坐标</param>
            /// <param name="renderCamera">相机</param>
            /// <returns>anchors为中心点的坐标</returns>
            public static Vector2 ScreenPointToAnchoredPosition(RectTransform baseRect, Vector3 screenPosition, Camera renderCamera = null)
            {
                Vector2 localPoint = Vector2.zero;
                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, renderCamera, out localPoint))
                {
                    Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
                    return localPoint + pivotOffset;//- (target.anchorMax * baseRect.sizeDelta) 
                }
                return Vector2.zero;
            }

            public static void SetScreenPointToAnchoredPosition(RectTransform baseRect, Vector3 screenPosition, RectTransform target, Camera renderCamera = null)
            {
                Vector2 localPoint = Vector2.zero;
                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(baseRect, screenPosition, renderCamera, out localPoint))
                {
                    Vector2 pivotOffset = baseRect.pivot * baseRect.sizeDelta;
                    target.anchorMax = new Vector2(0.5f, 0.5f);
                    target.anchorMin = new Vector2(0.5f, 0.5f);
                    target.anchoredPosition = localPoint + pivotOffset;
                }
            }
            **/
#if UNITY_EDITOR
            public static float GetAnimatorStateDurationInEditor(Animator animator, string clipName)
            {
                var duration = 0f;
                var controller = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
                if (controller == null)
                {
                    return duration;
                }
                var layer = controller.layers[0];
                foreach (var item in layer.stateMachine.states)
                {
                    if (item.state.name != clipName) continue;
                    float speed = item.state.speed;
                    var ani = item.state.motion as AnimationClip;
                    if (ani == null)
                    {
                        return duration;
                    }
                    duration = ani.length;
                    return duration * speed;
                }
                return duration;
            }
            public static void ClearConsole()
            {
                System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(UnityEditor.SceneView));
                System.Type type = assembly.GetType("UnityEditor.LogEntries");
                if (type == null) return;
                MethodInfo method = type.GetMethod("Clear");
                if (method == null) return;
                method.Invoke(null, null);
            }
            public static string GetAssetPath(GameObject target)
            {
                if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(target))
                {
                    return UnityEditor.AssetDatabase.GetAssetPath(target);
                }
                if (UnityEditor.PrefabUtility.IsPartOfPrefabInstance(target))
                {
                    var prefabAsset = UnityEditor.PrefabUtility.GetCorrespondingObjectFromOriginalSource(target);
                    return UnityEditor.AssetDatabase.GetAssetPath(prefabAsset);
                }
#if UNITY_2021_1_OR_NEWER
                var prefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetPrefabStage(target);
                if (prefabStage != null)
                {
                    return prefabStage.assetPath;
                }
#else
                var prefabStage = UnityEditor.Experimental.SceneManagement.PrefabStageUtility.GetPrefabStage(target);
                if (prefabStage != null)
                {
                    return prefabStage.assetPath;
                }
#endif
                return string.Empty;
            }
            public static List<AnimationState> GetAnimationStates(Animation animation)
            {
                var list = new List<AnimationState>();
                foreach (var item in animation)
                {
                    if (item is AnimationState state)
                    {
                        list.Add(state);
                    }
                }
                return list;
            }
            public static List<UnityEditor.Animations.AnimatorState> GetAnimatorClips(Animator animator, int layer = 0)
            {
                var list = new List<UnityEditor.Animations.AnimatorState>();
                var controller = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
                if (controller != null)
                {
                    if (controller.layers.Length > layer)
                    {
                        foreach (var item in controller.layers[layer].stateMachine.states)
                        {
                            list.Add(item.state);
                        }
                    }
                }
                return list;
            }

#endif

            public static float GetAnimatorNormalizedTime(Animator animator, string clipName)
            {
                var info = animator.GetCurrentAnimatorStateInfo(0);
                if (info.IsName(clipName))
                {
                    return info.normalizedTime;
                }
                return -1f;
            }
            public static bool IsAnimatorFinish(Animator animator, string clipName)
            {
                return GetAnimatorNormalizedTime(animator, clipName) >= 1f;
            }
            public static bool IsAnimatorStatePlaying(Animator animator, string clipName)
            {
                var info = animator.GetCurrentAnimatorStateInfo(0);
                return info.IsName(clipName);
            }
            public static float GetAnimatorStateDuration(Animator animator, string clipName)
            {
                var info = animator.GetCurrentAnimatorStateInfo(0);
                if (info.IsName(clipName))
                {
                    return info.length * info.speed;
                }
                return 0f;
            }
            public static void CreateChild(Transform parent, int nowCount, int targetCount, Action createAction)
            {
                if (createAction == null) return;
                nowCount = Mathf.Max(0, nowCount);
                targetCount = Mathf.Max(0, targetCount);
                var addCount = targetCount - nowCount;
                while (addCount-- > 0)
                {
                    createAction.Invoke();
                }
                var removeCount = nowCount - targetCount;
                while (removeCount-- > 0)
                {
                    var id = nowCount - removeCount - 1;
                    var item = parent.GetChild(id);
                    item.gameObject.SetActive(false);
                }
            }
            /*
            public static byte[] Hash128ToBytes(Hash128 hash128)
            {
                var data = MemoryMarshal.Cast<Hash128, byte>(new[] { hash128 });
                var len = data.Length;
                var result = new byte[len];
                for (var i = 0; i < len; i++)
                {
                    result[i] = data[i];
                }
                return result;
            }
            public static ulong[] ConvertHash128ToUlongs(Hash128 hash128)
            {
                ulong[] ulongs = new ulong[2];
                byte[] bytes = Hash128ToBytes(hash128);
                Array.Reverse(bytes);
                // 将 byte[] 中的值转换为两个 ulong
                ulongs[0] = BitConverter.ToUInt64(bytes, 0);
                ulongs[1] = BitConverter.ToUInt64(bytes, 8);
                return ulongs;
            }
            */
            public static void ConvertHash128ToInt(Hash128 hash128, out int a, out int b)
            {
                var str = hash128.ToString();
                var p1 = str.Substring(0, 16);
                var p2 = str.Substring(16);
                a = p1.GetHashCode();
                b = p2.GetHashCode();
            }
            public static string ConvertMd5Hash128(string hex)
            {
                int length = hex.Length;
                byte[] bytes = new byte[length / 2];
                for (int i = 0; i < length; i += 2)
                {
                    bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
                }

                // 使用 SHA512 算法进行哈希
                using SHA512 sha512 = SHA512.Create();
                byte[] hashBytes = sha512.ComputeHash(bytes);

                // 取哈希值的前 128 位
                byte[] hash128Bytes = new byte[16];
                for (int i = 0; i < 16; i++)
                {
                    hash128Bytes[i] = hashBytes[i];
                }

                // 将字节数组转换为字符串
                string hash128Str = BitConverter.ToString(hash128Bytes);
                return hash128Str.Replace("-", "");
            }
            /*
            // 将 Hash128 转换为两个 ulong
            public static ulong[] ConvertHash128ToUlongs(Hash128 hash128)
            {
                ulong[] ulongs = new ulong[2];

                // 使用 UnsafeUtility.GetAddressOfPinnedArrayElement 获取内存地址
                byte* address = (byte*)UnsafeUtility.GetAddressOfPinnedArrayElement(MemoryMarshal.Cast<Hash128, byte>(new[] { hash128 }).ToArray(), 0);

                // 将内存地址转换为 IntPtr 并使用 Marshal.Copy 方法复制到 byte[] 中
                byte[] bytes = new byte[16];
                Marshal.Copy(new IntPtr(address), bytes, 0, 16);

                // 将 byte[] 反转，因为 byte[] 中的顺序和 ulong 的顺序不同
                Array.Reverse(bytes);

                // 将 byte[] 中的值转换为两个 ulong
                ulongs[0] = BitConverter.ToUInt64(bytes, 0);
                ulongs[1] = BitConverter.ToUInt64(bytes, 8);

                return ulongs;
            }
            */
            public static ByteArray ReadTextAssetToByteArray(TextAsset value)
            {

#if UNITY_2021_1_OR_NEWER
                var data = value.GetData<byte>();
                var buffer = new ByteArray(data.Length);
                NativeArray<byte>.Copy(data, buffer.Buffer.Buffer, data.Length);
                return buffer;
#else
                return new ByteArray(value.bytes);
#endif
            }
            public static ByteArray ReadTextAssetToByteArray(TextAsset value, ByteArray target)
            {

#if UNITY_2021_1_OR_NEWER
                var data = value.GetData<byte>();
                if (target == null)
                {
                    target = new ByteArray(data.Length);
                }
                target.Buffer.SetSize(data.Length);
                NativeArray<byte>.Copy(data, target.Buffer.Buffer, data.Length);
                return target;
#else
                if (target == null)
                {
                    target = new ByteArray(10240);
                }
                target.Buffer.Write<byte>(0, value.bytes);
                return target;
#endif
            }

            public static void WriteAllBytes(string filePath, DownloadHandler downloadHandler)
            {
#if UNITY_2021_1_OR_NEWER
                Utils.File.WriteAllBytes(filePath, downloadHandler.nativeData);
#else
                Utils.File.WriteAllBytes(filePath, downloadHandler.data);
#endif
            }
            public static int GetDownloadHandlerSize(DownloadHandler downloadHandler)
            {
#if UNITY_2021_1_OR_NEWER
                return downloadHandler.nativeData.Length;
#else
                return downloadHandler.data.Length;
#endif
            }

            private static Dictionary<string, Stopwatch> _watchTime = new Dictionary<string, Stopwatch>();
            public static void StartWatchTime(string tag)
            {
                if (_watchTime.ContainsKey(tag))
                {
                    UnityEngine.Debug.LogError("已存在 " + tag);
                    return;
                }
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                _watchTime.Add(tag, stopwatch);
                if (_watchTime.Count == 50)
                {
                    UnityEngine.Debug.LogError("数量超过50 检查用法是否调用 StopWatchTime");
                }
            }
            public static long StopWatchTime(string tag)
            {
                if (_watchTime.TryGetValue(tag, out var stopwatch))
                {
                    _watchTime.Remove(tag);
                    return stopwatch.ElapsedMilliseconds;
                }
                UnityEngine.Debug.LogError("不存在 " + tag);
                return 0;
            }
            public static void AddUICameraToMainCamera(Camera mainCamera, Camera uiCamera)
            {
                if (mainCamera == null || uiCamera == null)
                {
                    return;
                }
                if (mainCamera == uiCamera)
                {
                    return;
                }
                /*
                var data = UnityEngine.Rendering.Universal.CameraExtensions.GetUniversalAdditionalCameraData(mainCamera);
                if (data != null)
                {
                    var list = data.cameraStack;
                    if (!list.Contains(uiCamera))
                    {
                        list.Add(uiCamera);
                    }
                }
                */
            }
            /// <summary>
            /// 根据当前屏幕尺寸适配垂直FOV
            /// </summary>
            /// <param name="DesignResolution">设计宽高尺寸</param>
            /// <param name="DesignVerticalFOV">设计垂直FOV</param>
            /// <returns>当前垂直FOV</returns>
            public static float AdjustVerticalFOV(Vector2 DesignResolution, float DesignVerticalFOV)
            {
                // 计算当前屏幕宽高比  
                float currentAspectRatio = (float)Screen.width / Screen.height;
                // 计算在参考分辨率下的宽高比  
                float referenceAspectRatio = DesignResolution.x / DesignResolution.y;
                return 2f * Mathf.Atan(Mathf.Tan(DesignVerticalFOV * Mathf.Deg2Rad * 0.5f) * (referenceAspectRatio / currentAspectRatio)) * Mathf.Rad2Deg; ;
            }
			public static void SetRenderPipline(UnityEngine.Rendering.RenderPipelineAsset asset)
            {
                QualitySettings.renderPipeline = asset;
                UnityEngine.Rendering.GraphicsSettings.renderPipelineAsset =asset;
            }
        }

    }
}